#ifndef __MP4__PARSER__
#define __MP4__PARSER__

#ifdef __Win32__
#pragma warning(disable:4786)
#endif


#include <stdio.h>
#include <vector>
#include <map>
#include <list>
#include "OSHeaders.h"
#include "OSMacro.h"
#include "atom.h"
#include "OSMutex.h"
#include <string>

using namespace std;

struct SBitBufMap;
class TrackInfo;
class Mp4Parser
{
	friend class TrackInfo;
public:
	Mp4Parser(const char* v_FileName);
	~Mp4Parser();
	Bool Initialize();
public:
	Bool GetSdpInfo(Char* v_sdpInfo, const char * v_LocalIP);
	TrackInfo* GetVideoTrack();
	TrackInfo* GetVideoHintTrack();
	TrackInfo* GetAudioTrack();
	TrackInfo* GetAudioHintTrack();
	UInt64	   GetRangeTime();
	vector<TrackInfo*> GetTrackList();
	UInt32 GetTimeScale();
	UInt32 GetDuration();
	Bool HasHint();
	Bool HasVideo();
	Bool HasAudio();

	Int32 GetBufferMap(SBitBufMap & outBufMap);

private:
	Bool Parser();
	Bool ReadMp4File(UInt32 &v_size,UInt32 &v_type);
	Bool ParserAtom(UChar* v_AtomBuf,UInt32 v_AtomLen);	
private:
	FILE* m_fp;
	std::string m_FileName;
	UChar* m_MoovBuf;
	UInt32 m_MoovLen;
private:
	UInt32		m_TimeScale;
	UInt32		m_Duration;
	Char		m_sdpInfo[RFS_SDP_LEN];
	TrackInfo*	m_VideoTrack;
	TrackInfo*	m_AudioTrack;
	TrackInfo*	m_VideoHintTrack;
	TrackInfo*	m_AudioHintTrack;
	vector<TrackInfo*> m_TrackList;
private:
	Bool m_hasHint;
	Bool m_hasVideo;
	Bool m_hasAudio;
};

///////////////////
struct sample_info_t
{
	//UInt32	id;
	UInt32	offset;	
	UInt32	timestamp;
	UInt32    sizeandkey;
	//UInt32  size;
	//Bool	iskey;
	sample_info_t()
	{
		//id = 0;
		offset = 0;		
		timestamp = 0;
		//size = 0;
		//iskey = 0;
		sizeandkey = 0;
	}
	void SetSize(UInt32 v_size)
	{
		sizeandkey &= 0xFF000000;
		sizeandkey |= (v_size & 0x00FFFFFF);
	}
	void SetKey(Bool v_key)
	{
		sizeandkey &= 0x00FFFFFF;
		sizeandkey |= v_key ? 0xFF000000 : 0x00000000;
	}
	UInt32 GetSize()
	{
		return sizeandkey & 0x00FFFFFF;
	}
	Bool GetKey()
	{
		return sizeandkey & 0xFF000000 ? TRUE : FALSE;
	}
};

class Mp4Parser;

class TrackInfo
{
	friend class Mp4Parser;
public:
	TrackInfo(Mp4Parser* v_Mp4Parser);
	~TrackInfo();
	Bool Initialize(UChar* v_AtomBuf,UInt32 v_AtomLen);
public:
	UInt32 GetTrackID();
	UInt32 GetTrackType();
	UInt32 GetTimeScale();
	UInt32 GetDuration();
	Bool   IsHintTrack();
	const vector<sample_info_t*>& GetSampleList();
	Char* GetSdpText();
private:
	Bool ParserAtom(UChar* v_AtomBuf,UInt32 v_AtomLen);
	Bool ParserHint(UChar* v_AtomBuf);
	Bool ParserStts(UChar* v_AtomBuf);
	Bool ParserStss(UChar* v_AtomBuf);
	Bool ParserStsc(UChar* v_AtomBuf);
	Bool ParserStsz(UChar* v_AtomBuf);
	Bool ParserStco(UChar* v_AtomBuf);
public:
	vector<sample_info_t*> m_SampleList;
private:
	map<UInt32,list<UInt32> > m_SampleToChunk;
private:
	Mp4Parser* m_Mp4Parser;
	UInt32	m_trackid;
	UInt32	m_tracktype;
	UInt32	m_timescale;
	UInt32	m_duration;
	Char	m_sdpInfo[RFS_SDP_LEN];
	UInt32	m_HintRefTrackID;
	Bool	m_IsHint;
};

///////////////////
#endif

